﻿using UnityEngine;
using System.Collections;
using System.Collections.Generic;

enum CameraState
{
    Menu,
    Game,
    TransitionToGame,
    TransitionToMenu
}

public class CameraBehaviour : MonoBehaviour {

    public Transform aim;
    public GameManager gameManager;

    private Transform[] path;
    private int pathIndex = 0;
    private Vector3 nextPosition;
    private CameraState currentState;
    private Vector3 goalPosition;
    private Vector3 startGamePosition;
    private Quaternion lookRotation;
    private float speed = 100;
    private float rotSpeed = 20;
    private float zoomRange = 20;
    private float acceleration = 2;

    private Vector3 menuPosition;
    public Vector3 MenuPosition
    {
        get { return menuPosition; }
    }

    private Quaternion menuRotation;
    public Quaternion MenuRotation
    {
        get { return menuRotation; }
    }

    //Game camera movements
    private int screenBorderOffset = 20;
    private Vector3 gameMovementSpeed;

    private Rect levelBorder;

    public Rect LevelBorder
    {
        get { return levelBorder; }
        set { levelBorder = value; }
    }

    public void setBorders(Rect nborder)
    {
        levelBorder = nborder;
    }

	// Use this for initialization
	void Start () {
        currentState = CameraState.Menu;
        menuPosition = transform.position;
        menuRotation = transform.rotation;

        EventManager<Level>.AddListener("set level", OnSetLevel);
        EventManager <EndLevelStat>.AddListener("end level", onLevelEnd);
	}
	
	// Update is called once per frame
	void Update () {
	    switch(currentState)
        {
            case CameraState.Menu:

                break;

            case CameraState.Game:
                if (Input.mousePosition.x < screenBorderOffset || Input.GetKey(KeyCode.LeftArrow))
                {
                    if(transform.position.z < levelBorder.yMax)
                        gameMovementSpeed.z = acceleration;
                }
                if (Input.mousePosition.x > Screen.width - screenBorderOffset || Input.GetKey(KeyCode.RightArrow))
                {
                    if (transform.position.z > levelBorder.yMin)
                        gameMovementSpeed.z = -acceleration;
                }
                if (Input.mousePosition.y < screenBorderOffset || Input.GetKey(KeyCode.DownArrow))
                {
                    if (transform.position.x > levelBorder.xMin)
                        gameMovementSpeed.x = -acceleration;
                }
                if (Input.mousePosition.y > Screen.height - screenBorderOffset || Input.GetKey(KeyCode.UpArrow))
                {
                    if (transform.position.x < levelBorder.xMax)
                        gameMovementSpeed.x = acceleration;
                }
                if (Input.GetAxis("Mouse ScrollWheel") < 0 && startGamePosition.y - transform.position.y < zoomRange) // back
                {
                    gameMovementSpeed.y = -2 * acceleration;
                }
                if (Input.GetAxis("Mouse ScrollWheel") > 0 &&  transform.position.y - startGamePosition.y < zoomRange) // forward
                {
                    gameMovementSpeed.y = +2 * acceleration;
                }
                /*if (Input.GetMouseButtonDown(1))
                {
                    rightClickPosition = Input.mousePosition;
                }
                if(Input.GetKey(KeyCode.Mouse1))
                {
                    Vector3 delta = rightClickPosition - Input.mousePosition;
                    transform.position = new Vector3((rightClickPosition.y + delta.y)/5, transform.position.y, -(rightClickPosition.x + delta.x)/5); 
                }*/
                transform.Translate(gameMovementSpeed, Space.World);
                gameMovementSpeed = Vector3.zero;

                break;

            case CameraState.TransitionToGame:
                updateSpeed();

                if (Vector3.Distance(transform.position, goalPosition) < 1)
                {
                    startGamePosition = goalPosition;
                    currentState = CameraState.Game;
                    EventManager.Raise("start level");
                }
                else
                {
                    if (Vector3.Distance(transform.position, nextPosition) < 1)
                    {
                        if (pathIndex != path.Length - 1)
                        {
                            pathIndex++;
                        }
                        nextPosition = path[pathIndex].transform.position;
                    }
                    //Point to goal
                    aim.LookAt(goalPosition);
                    //lock y rotation
                    aim.rotation = Quaternion.Euler(aim.rotation.eulerAngles.x - 20, 90, aim.rotation.eulerAngles.z);
                    //Rotate to the goal
                    transform.rotation = Quaternion.Slerp(transform.rotation, aim.rotation, Time.deltaTime * rotSpeed);
                    //Follow the path
                    transform.position = Vector3.Lerp(transform.position, nextPosition, speed * Time.deltaTime);
                }
                break;

            case CameraState.TransitionToMenu:
                if (Vector3.Distance(transform.position, menuPosition) < 1)
                {
                    currentState = CameraState.Menu;
                }
                else
                {
                    aim.rotation = Quaternion.Euler(aim.rotation.eulerAngles.x - 20, 90, aim.rotation.eulerAngles.z);
                    transform.position = Vector3.Lerp(transform.position, nextPosition, speed * Time.deltaTime);
                }
                break;
        }
	}

    private void updateSpeed()
    {
        //The speed depends on the distance with a minimum for close translation
        speed = Vector3.Distance(transform.position, goalPosition) / 100;
        if(speed < 5)
        {
            speed = 5;
        }
    }

    public void setPath(Transform[] newPath)
    {
        goalPosition = newPath[newPath.Length - 1].transform.position;
        path = newPath;
        currentState = CameraState.TransitionToGame;
        nextPosition = path[pathIndex].transform.position;
    }

    public bool isInTransition()
    {
        return (currentState == CameraState.TransitionToMenu || currentState == CameraState.TransitionToGame);
    }


    private void OnSetLevel(Level nLevel)
    {
        setPath(nLevel.CameraPath);
        setBorders(nLevel.Border);
    }

    private void onLevelEnd(EndLevelStat stat)
    {
        nextPosition = menuPosition;
        transform.rotation = menuRotation;
        currentState = CameraState.TransitionToMenu;
    }
}
